﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrokerBase.Lib.Policy;
using NHibernate;
using BrokerBase.Lib.Product;
using BrokerBase.Lib.Product.RateFactorConverter;
using System.Data.OleDb;
using System.Data;
using BrokerBase.Lib.Person;

namespace BrokerBase.Lib.Tool
{
    public static class PolicyUtil
    {

        public static bool SetPolicyRate(IPolicy policy, ISession sess)
        {
            bool isSuccess = false;

            if (policy.Product.IsLadderAmount)
            {
                isSuccess=SetPolicyFixRateWithLadder(policy, sess);
            }
            else if (policy.Product.CanOverPeriod)
            {
                isSuccess = SetPolicyFixRateWithCanOverPeriod(policy, sess);
            }
            else
            {
                isSuccess = SetPolicyFixRateWithoutLadder(policy, sess);
            }

            return isSuccess;
        }

        private static bool SetPolicyFixRateWithoutLadder(IPolicy policy, ISession sess)
        {
            string key1=policy.SelectedRowRateFactors[policy.Product.RowRateFactors[0].Name];

            string key2=policy.SelectedRowRateFactors[policy.Product.RowRateFactors[1].Name];

            double? value = LoadRate(policy.Product, policy.GetColKey(), key1, key2, sess);
            double v = value == null ? 0 : value.Value;

            switch (policy.Product.RateType)
            {
                case RateType.Amount:
                    policy.Amount = policy.FixFee / policy.SelectedBasicAmount.Basic * v * policy.Product.TimeUnit.Coefficient;
                    break;

                case RateType.Premium:
                    policy.FixFee = policy.Amount / policy.SelectedBasicAmount.Basic * v * policy.Product.TimeUnit.Coefficient;
                    break;
            }

            policy.FixFees = new double[policy.PaymentPeriodLength];

            for (int i = 0; i < policy.PaymentPeriodLength; i++)
            {
                policy.FixFees[i] = policy.FixFee;
            }

            return v != 0;
        }

        private static bool SetPolicyFixRateWithCanOverPeriod(IPolicy policy,ISession sess)
        {
            IRateFactor rf = policy.Product.ColRateFactors.FirstOrDefault(p => p.IsLadderConverter);

            IList<string[]> rowKeys = new List<string[]>();
            //IList<string[]> rowKeysAll = new List<string[]>();

            //IPerson person = policy.Target == PolicyTarget.Holder ? policy.Owner.Holder : policy.Owner.Insurant;

            int personAge = policy.Target == PolicyTarget.Holder ? policy.Owner.HolderAge : policy.Owner.InsurantAge;

            for (int i = 0; i < policy.PaymentPeriodLength; i++)
            {
                string[] rowKey = AgeConverter.GetKeys(policy, personAge + i, RateFactorAxis.Row);
                rowKey[1] = rowKey[1] == null ? string.Empty : rowKey[1];
                rowKeys.Add(rowKey);
            }

            double?[] vs = LoadRatesWithCanOverPeriod(policy, policy.GetColKey(), rowKeys, sess);

            if (policy.Product.RateType == RateType.Amount)
                throw new Exception("跨支付期的产品不支持费率是保额类型");

            policy.FixFees = new double[policy.PaymentPeriodLength];
            for (int i = 0; i < vs.Count(); i++)
            {
                double v = vs[i] == null ? 0 : vs[i].Value;
                policy.FixFees[i] = policy.Amount / policy.SelectedBasicAmount.Basic * v * policy.Product.TimeUnit.Coefficient;
            }

            policy.FixFee = policy.FixFees[0];

            return vs[0] != 0;
        }

        private static bool SetPolicyFixRateWithLadder(IPolicy policy, ISession sess)
        {
            string key1 = policy.SelectedRowRateFactors[policy.Product.RowRateFactors[0].Name];

            string key2 = policy.SelectedRowRateFactors[policy.Product.RowRateFactors[1].Name];

            IRateFactor rf=policy.Product.ColRateFactors.FirstOrDefault(p=>p.IsLadderConverter);

            double[] rates =new double[ policy.Product.BasicAmounts.Count];
            double[] amts=new double[ policy.Product.BasicAmounts.Count];

            double fee = 0;

            double amount=policy.Amount;

            IBasicAmount fristBa=policy.Product.BasicAmounts[0];

            IEnumerable<IBasicAmount> basicAmountOrder = policy.Product.BasicAmounts.OrderByDescending(p => p.Basic);


            //for (int i = rates.Count() - 1; i >= 0; i--)
            //{
            //    IBasicAmount ba = policy.Product.BasicAmounts[i];

            //    policy.SelectedColRateFactors[rf.Name] = ba.Name;

            //    double ladderAmt = i==0? amount: amount - ba.Basic;

            //    if (ladderAmt > 0)
            //    {
            //        double? v = LoadRate(policy.Product, policy.GetColKey(), key1, key2, sess);
            //        rates[i] = v == null ? 0 : v.Value;

            //        int b = 1;

            //        if (policy.Product.UnitType == UnitType.Qty)
            //            b = 1;
            //        else
            //            b = ba.Basic;

            //        fee += ladderAmt /b * rates[i];
            //        amount -= ladderAmt;
            //    }


            //}

            for (int i = 0; i < rates.Count(); i++)
            {
                IBasicAmount ba = policy.Product.BasicAmounts[i];

                policy.SelectedColRateFactors[rf.Name] = ba.Name;

                double? v = LoadRate(policy.Product, policy.GetColKey(), key1, key2, sess);

                rates[i] = v == null ? 0 : v.Value;

                double ladderAmt = i == rates.Count() - 1 ? amount : ba.Basic;

                int b = 1;
                if (policy.Product.UnitType == UnitType.Qty)
                    b = 1;
                else
                    b = ba.Basic;

                fee += ladderAmt /b * (v == null ? 0 : v.Value);

                amount = amount - ladderAmt;

            }

            policy.FixFee = fee;
            policy.FixFees = new double[policy.PaymentPeriodLength];
            for (int i = 0; i < policy.PaymentPeriodLength; i++)
            {
                policy.FixFees[i] = fee;
            }

            return fee != 0;
        }

        public static double? LoadRate(IProduct product, string colCmbKey, string rowKey1, string rowKey2,ISession sess)
        {
            IList<string> keys = product.GetColRateKeys();

            string key = colCmbKey;

            double? value = null;

            int index = -1;

            index = keys.IndexOf(key);

            for (int i = 0; i < keys.Count; i++)
            {
                if (key == keys[i])
                {
                    index = i;
                    break;
                }
            }

            if (index == -1)
                return null;

            int warpIndex = index / 100;

            int colIndex = index % 100;


            string col = "Col" + colIndex;

            string hql = string.Format("select r.{0} from RateRow as r where r.Owner.Id={1} and r.Key1='{2}' and r.Key2='{3}' and r.WrapIndex={4}", col, product.Id, rowKey1, rowKey2, warpIndex);

            IQuery q = sess.CreateQuery(hql);

            IList<double?> ds = q.List<double?>();

            value = sess.CreateQuery(hql).UniqueResult<double?>();

            return value;
        }

        public static double?[] LoadRatesWithCanOverPeriod(IPolicy policy,string colCmbKey,IList<string[]> rowKeys, ISession sess)
        {

            Tuple<int, int> indexCmb = GetIndexByColCombs(policy.Product, colCmbKey);

            if (indexCmb.Item2 == -1)
                return null;

            int warpIndex = indexCmb.Item1;

            int colIndex = indexCmb.Item2;

            string col = "Col" + colIndex;

            string hql = string.Format("select r.Key1,r.Key2,r.{0} from RateRow as r where r.Owner.Id={1} and r.WrapIndex={2}", col, policy.Product.Id, warpIndex);

            double?[] values = new double?[rowKeys.Count()];

            IQuery q = sess.CreateQuery(hql);

            IList<object[]> ds = q.List<object[]>();


            for (int i = 0; i < rowKeys.Count; i++)
            {
                string k1=rowKeys[i][0];
                string k2=rowKeys[i][1];

                object[] tmp = ds.FirstOrDefault(p => p[0].ToString() == k1 && p[1].ToString() == k2);

                double f = 0.0f;

                if (tmp != null)
                {
                    f = Convert.ToDouble(tmp[2]);
                    
                }


                values[i] = f;
            }

            return values;
        }

        public static double? LoadRate(IPolicy policy, ISession sess)
        {
            IList<string> keys = policy.Product.GetColRateKeys();

            string key = policy.GetColKey();

            double? value = null;

            int index = -1;

            index = keys.IndexOf(key);

            for (int i = 0; i < keys.Count; i++)
            {
                if (key == keys[i])
                {
                    index = i;
                    break;
                }
            }

            if (index == -1)
                return null;

            int warpIndex = index / 100;

            int colIndex = index % 100;

            string key1=policy.SelectedRowRateFactors[policy.Product.RowRateFactors[0].Name];

            string key2=string.Empty;

            if(policy.SelectedRowRateFactors.Count>1)
                key2 = policy.SelectedRowRateFactors[policy.Product.RowRateFactors[1].Name] + string.Empty;

            string col = "Col" + colIndex;

            string hql = string.Format("select r.{0} from RateRow as r where r.Owner.Id={1} and r.Key1='{2}' and r.Key2='{3}' and r.WrapIndex={4}",col,policy.Product.Id, key1, key2,warpIndex);

            IQuery q = sess.CreateQuery(hql);

            IList<double?> ds = q.List<double?>();

            value=sess.CreateQuery(hql).UniqueResult<double?>();

            return value;
        }

        public static IList<IPlanPayPeriod> LoadRemindPayDate(DateTime date, int preDay, ISession sess)
        {
            string hql = string.Format("from PlanPayPeriod as p where p.Scheme.CheckTime is not null and p.PayTime>='{0}' and p.PayTime<'{1}'", date.ToString("yyyy-MM-dd"), date.AddDays(preDay).ToString("yyyy-MM-dd"));

            IList<IPlanPayPeriod> pps = sess.CreateQuery(hql).List<IPlanPayPeriod>();

            return pps;
        }

        public static string GetExcelCell(string file, string sheetName, int colIndex, int whereColIndex, string whereValue)
        {
            try
            {
                string cnn = string.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR=No;IMEX=1';", file);

                string colName = "F" + colIndex;
                string whereColName = "F" + whereColIndex;

                string sql = string.Format("select {0} from  [{1}$] where {2}='{3}'", colName, sheetName, whereColName, whereValue);

                OleDbDataAdapter cmd = new OleDbDataAdapter(sql, cnn);
                DataSet ds = new DataSet();
                cmd.Fill(ds, "sheet1");

                IList<object> ls = new List<object>();

                string v = ds.Tables[0].Rows[0][0].ToString();

                return v;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 获得保险期限的描述
        /// </summary>
        /// <param name="policyLight"></param>
        /// <returns></returns>
        public static string GetInsurancePeriodDescription(IPolicyLight policyLight)
        {
            string result = null;

            if (policyLight.Policy != null)
            {
                if (policyLight.Policy.OverInsurancePeriod > 1)
                    result = policyLight.Policy.InsurancePeriodLength + "年期";
                else
                    result = policyLight.Policy.SelectedInsurancePeriod.Name;
            }
            else
            {
                switch (policyLight.InsurancePeriodStyle)
                {
                    case InsurancePeriodStyle.Age:
                        result = "到" + policyLight.InsurancePeriodValue + "岁";
                        break;
                    case InsurancePeriodStyle.Period:
                        result = policyLight.InsurancePeriodValue + "年期";
                        break;
                    case InsurancePeriodStyle.Lifetime:
                        result = "终身";
                        break;
                    default:
                        throw new Exception("自定义保险的保险期限不支持"+policyLight.InsurancePeriodStyle);
                    
                }
            }

            return result;
        }
        /// <summary>
        /// 获得付款期限的描述
        /// </summary>
        /// <param name="policyLight"></param>
        /// <returns></returns>
        public static string GetPaymentPeriodDescription(IPolicyLight policyLight)
        {
            string result = null;

            if (policyLight.Policy != null)
            {
                if (policyLight.Policy.OverPaymentPeriod > 1)
                    result = policyLight.Policy.PaymentPeriodLength + "年期";
                else
                    result = policyLight.Policy.SelectedPaymentPeriod.Name;
            }
            else
            {
                switch (policyLight.PaymentPeriodStyle)
                {
                    case PaymentPeriodStyle.Age:
                        result = "到" + policyLight.PaymentPeriodValue + "岁";
                        break;
                    case PaymentPeriodStyle.Period:
                        result = policyLight.PaymentPeriodValue + "年期";
                        break;
                    default:
                        throw new Exception("自定义保险的付款期限不支持" + policyLight.PaymentPeriodStyle);
                }
            }


            return result;
        }

        public static int GetInsurancePeriodLength(IBasePolicy policy)
        {
            int p = 0;

            if (policy is IPolicy)
            {
                IPolicy py= policy as IPolicy;

                IInsurancePeriod ip = py.SelectedInsurancePeriod;

                switch (ip.Style)
                {
                    case InsurancePeriodStyle.Lifetime:
                        if (policy.Target == PolicyTarget.Insurant)
                            p = policy.MaxInsuranceAge - policy.Owner.InsurantAge+1;
                        else
                            p = policy.MaxInsuranceAge - policy.Owner.HolderAge +1;
                        break;
                    case InsurancePeriodStyle.Period:
                        p = ip.Value;
                        break;
                    case InsurancePeriodStyle.Age:
                        p = ip.Value - py.Owner.InsurantAge + 1;
                        break;
                    case InsurancePeriodStyle.EqualPayPeriod:
                        p = py.PaymentPeriodLength;
                        break;
                    case InsurancePeriodStyle.EqualBasic:
                        p = py.Owner.BasicPolicy.InsurancePeriodLength;
                        break;
                }

                //return p * OverInsurancePeriod;//再乘以OverInsurancePeriod是不对的，重复了，感觉OverInsurancePeriod这个概念是多余的。
                return p ;
            }
            else if (policy is IPolicyLight)
            {
                IPolicyLight pl = policy as IPolicyLight;

                switch (pl.InsurancePeriodStyle)
                {
                    case InsurancePeriodStyle.Age:
                        p = pl.InsurancePeriodValue - pl.Owner.InsurantAge + 1;
                        break;
                    case InsurancePeriodStyle.Period:
                        p = pl.InsurancePeriodValue;
                        break;
                    default:
                        throw new Exception("自定义保险不支持:"+pl.InsurancePeriodStyle);
                }

                return p;
            }
            else
            {
                throw new Exception("不是保险类型!");
            }
        }

        /// <summary>
        /// 计算付款期限
        /// </summary>
        /// <param name="policyLight"></param>
        /// <returns></returns>
        public static int GetPaymentPeriodLength(IBasePolicy policy)
        {
            int p = 0;

            if (policy is IPolicy)
            {
                IPolicy py = policy as IPolicy;

                IPaymentPeriod pp = py.SelectedPaymentPeriod;
                switch (pp.Style)
                {
                    case PaymentPeriodStyle.Once:
                        p = 1;
                        break;
                    case PaymentPeriodStyle.Period:
                        p = pp.Value;
                        break;
                    case PaymentPeriodStyle.Age:
                        p = pp.Value - py.Owner.InsurantAge;
                        break;
                    case PaymentPeriodStyle.EqualInsPeriod:
                        p = py.InsurancePeriodLength;
                        break;
                    case PaymentPeriodStyle.EqualBasic:
                        p = py.Owner.BasicPolicy.PaymentPeriodLength;
                        break;
                    case PaymentPeriodStyle.Lifetime:
                        p = py.InsurancePeriodLength;
                        break;
                }

                return p * py.OverPaymentPeriod;
            }
            else if (policy is IPolicyLight)
            {
                IPolicyLight pl = policy as IPolicyLight;

                switch (pl.PaymentPeriodStyle)
                {
                    case PaymentPeriodStyle.Age:
                        p = pl.PaymentPeriodValue - pl.Owner.InsurantAge;
                        break;
                    case PaymentPeriodStyle.Period:
                        p = pl.PaymentPeriodValue;
                        break;
                    default:
                        throw new Exception("自定义保险不支持:" + pl.PaymentPeriodStyle);
                }

                return p;
            }
            else
            {
                throw new Exception("不是保险类型!");
            }

        }

        public static IDictionary<string,string> VerifyPoliyFixRate(IPolicy policy, IDictionary<string,string> cmbs,ISession sess,IList<object[]> rowRates)
        {
            IList<IRateFactor> colRateFactors=policy.Product.ColRateFactors;

            IDictionary<string, string> result = new Dictionary<string, string>();

            string colKeies = null;

            foreach (KeyValuePair<string, string> val in cmbs)
            {
                IRateFactor rf = colRateFactors.FirstOrDefault(p => p.Name == val.Key);

                if (rf.IsHasConverter )
                {
                    IRateFactorConverter conver = rf.ConverterInstance;

                    if (conver != null && conver.IsFixedProperty)
                    {
                        if (conver.GetItemByPolicy(policy) != val.Value)
                        {
                            result.Add(val.Key, val.Key + "不匹配!");
                        }
                    }
                }

                colKeies += colKeies == null ? val.Value : "-" + val.Value;

                
            }

            string rowName = policy.Product.RowRateFactors[0].Name;
            if (rowRates != null)
            {
                Tuple<int, int> indexcmb = PolicyUtil.GetIndexByColCombs(policy.Product, colKeies);

                if (indexcmb.Item2 >= 0)
                {
                    object o = rowRates[indexcmb.Item1][indexcmb.Item2 + 5];

                    if (o == null || Convert.ToDouble(o) <= double.Epsilon)
                    {
                        
                        result.Add("Row", rowName + "： 没有找到对应的费率");
                    }
                }

            }
            else
            {
                result.Add("Row", rowName + "： 没有找到对应的费率");
            }

            return result;
        }

        public static Tuple<int, int> GetIndexByColCombs(IProduct product, string colCmbKey)
        {
            IList<string> keys = product.GetColRateKeys();

            string key = colCmbKey;

            int index = -1;

            index = keys.IndexOf(key);

            for (int i = 0; i < keys.Count; i++)
            {
                if (key == keys[i])
                {
                    index = i;
                    break;
                }
            }

            if (index == -1)
                return null;

            int warpIndex = index / 100;

            int colIndex = index % 100;

            Tuple<int, int> result = new Tuple<int, int>(warpIndex,colIndex);

            return result;
        }

        public static IList<object[]> LoadRowRate(IProduct product, string key1, string key2, ISession sess)
        {

            string sql = string.Format("select * from Product_RateRow where ownerid={0} and key1='{1}' and key2='{2}' order by WrapIndex", product.Id, key1, key2);

            IList<object[]> rows=sess.CreateSQLQuery(sql).List<object[]>();


            return rows;
        }
    }
}
